﻿using System.Runtime.InteropServices;
using System;
using System.Linq;
using System.IO;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Windows.Media;
using System.Runtime.Serialization;
using System.Drawing.Imaging;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Specialized;
using System.ComponentModel;
using Color = System.Windows.Media.Color;

namespace DarkLight.Model
{
    [DataContract]
    public class Planet : Orthonormality, IEnvironment
    {
        //#region Data
        //private float _scaleDepth = 0.25f;
        //#endregion

        #region Constructors
        public Planet(float radius)
        {
            Moons = new ObservableCollection<Moon>();
            Moons.CollectionChanged += Moons_CollectionChanged;
            //this.InitializeComponent();
            this.Radius = radius;
        }
        #endregion

        #region Public Members
        [DataMember]
        [Required(ErrorMessage = "Name required")]
        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    RaisePropertyChanging("Name");
                    _name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }
        private string _name;

        [DataMember]
        public float Radius
        {
            get { return _radius; }
            set
            {
                if (_radius != value)
                {
                    RaisePropertyChanging("Radius");
                    _radius = value;
                    RaisePropertyChanged("Radius");
                }
            }
        }
        private float _radius;

        public SpaceRegion NearSpace
        {
            get { return _nearSpace; }
            set
            { 
                if (!object.ReferenceEquals(_nearSpace, value))
                {
                    RaisePropertyChanging("NearSpace");
                    _nearSpace = value;
                    RaisePropertyChanged("NearSpace");
                }
            }
        }
        private SpaceRegion _nearSpace;

        public SpaceRegion FarSpace
        {
            get { return _farSpace; }
            set
            {
                if (!object.ReferenceEquals(_farSpace, value))
                {
                    RaisePropertyChanging("FarSpace");
                    _farSpace = value;
                    RaisePropertyChanged("FarSpace");
                }
            }
        }
        private SpaceRegion _farSpace;

        [DataMember]
        public ObservableCollection<Moon> Moons { get; private set; }

        [DataMember]
        [Range(1.0, 50.0, ErrorMessage = "La valeur doit être comprise entre 0 et 50.")]
        public float PhongExponent
        {
            get { return _PhongExponent; }
            set 
            {
                if (_PhongExponent != value)
                {
                    RaisePropertyChanging("PhongExponent");
                    _PhongExponent = value;
                    RaisePropertyChanged("PhongExponent");
                }
            }
        }
        private float _PhongExponent = 1.0f;

        [DataMember]
        [Range(0, 10.0, ErrorMessage = "La valeur doit être comprise entre 0 et 10.")]
        public float PhongCoefficient
        {
            get { return _PhongCoefficient; }
            set
            {
                if (_PhongCoefficient != value)
                {
                    RaisePropertyChanging("PhongCoefficient");
                    _PhongCoefficient = value;
                    RaisePropertyChanged("PhongCoefficient");
                }
            }
        }
        private float _PhongCoefficient;

        [DataMember]
        [Range(0, 1.0, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float DiffuseCoefficient
        {
            get { return _DiffuseCoefficient; }
            set
            {
                if (_DiffuseCoefficient != value)
                {
                    RaisePropertyChanging("DiffuseCoefficient");
                    _DiffuseCoefficient = value;
                    RaisePropertyChanged("DiffuseCoefficient");
                }
            }
        }
        private float _DiffuseCoefficient;

        [DataMember]
        public bool HasClouds
        {
            get { return _HasClouds; }
            set
            {
                if (_HasClouds != value)
                {
                    RaisePropertyChanging("HasClouds");
                    _HasClouds = value;
                    RaisePropertyChanged("HasClouds");
                }
            }
        }
        private bool _HasClouds;

        [DataMember]
        [Range(0, 1.0, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float CloudsSpeed
        {
            get { return _CloudsSpeed; }
            set
            {
                if (_CloudsSpeed != value)
                {
                    RaisePropertyChanging("CloudsSpeed");
                    _CloudsSpeed = value;
                    RaisePropertyChanged("CloudsSpeed");
                }
            }
        }
        private float _CloudsSpeed;

        [DataMember]
        [Range(0.001, 0.01, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float CloudsHeight
        {
            get { return _CloudsHeight; }
            set
            {
                if (_CloudsHeight != value)
                {
                    RaisePropertyChanging("CloudsHeight");
                    _CloudsHeight = value;
                    RaisePropertyChanged("CloudsHeight");
                }
            }
        }
        private float _CloudsHeight = 0.001f;

        [DataMember]
        [Range(0, 1.0, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float CloudsOpacity
        {
            get { return _CloudsOpacity; }
            set
            {
                if (_CloudsOpacity != value)
                {
                    RaisePropertyChanging("CloudsOpacity");
                    _CloudsOpacity = value;
                    RaisePropertyChanged("CloudsOpacity");
                }
            }
        }
        private float _CloudsOpacity;

        [DataMember]
        public bool HasAtmosphere
        {
            get { return _HasAtmosphere; }
            set
            {
                if (_HasAtmosphere != value)
                {
                    RaisePropertyChanging("HasAtmosphere");
                    _HasAtmosphere = value;
                    RaisePropertyChanged("HasAtmosphere");
                }
            }
        }
        private bool _HasAtmosphere;

        [DataMember]
        [Range(0.01, 0.1, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float AtmosphereHeight
        {
            get { return _AtmosphereHeight; }
            set
            {
                if (_AtmosphereHeight != value)
                {
                    RaisePropertyChanging("AtmosphereHeight");
                    _AtmosphereHeight = value;
                    RaisePropertyChanged("AtmosphereHeight");
                }
            }
        }
        private float _AtmosphereHeight = 0.01f;
        
        [DataMember]
        [Range(0, 1.0, ErrorMessage = "La valeur doit être comprise entre 0 et 1.")]
        public float AtmosphereOpacity
        {
            get { return _AtmosphereOpacity; }
            set
            {
                if (_AtmosphereOpacity != value)
                {
                    RaisePropertyChanging("AtmosphereOpacity");
                    _AtmosphereOpacity = value;
                    RaisePropertyChanged("AtmosphereOpacity");
                }
            }
        }
        private float _AtmosphereOpacity;

        //[DataMember]
        public Color AtmosphereColor
        {
            get { return _AtmosphereColor; }
            set
            {
                if (_AtmosphereColor != value)
                {
                    RaisePropertyChanging("AtmosphereColor");
                    _AtmosphereColor = value;
                    RaisePropertyChanged("AtmosphereColor");
                }
            }
        }
        private Color _AtmosphereColor;

        public Bitmap DiffuseTexture
        {
            get { return _DiffuseTexture; }
            set
            {
                if (_DiffuseTexture != value)
                {
                    RaisePropertyChanging("DiffuseTexture");
                    _DiffuseTexture = value;
                    RaisePropertyChanged("DiffuseTexture");
                }
            }
        }
        private Bitmap _DiffuseTexture;

        public Bitmap GlowTexture
        {
            get { return _GlowTexture; }
            set
            {
                if (_GlowTexture != value)
                {
                    RaisePropertyChanging("GlowTexture");
                    _GlowTexture = value;
                    RaisePropertyChanged("GlowTexture");
                }
            }
        }
        private Bitmap _GlowTexture;

        public Bitmap BumpTexture
        {
            get { return _BumpTexture; }
            set
            {
                if (_BumpTexture != value)
                {
                    RaisePropertyChanging("BumpTexture");
                    _BumpTexture = value;
                    RaisePropertyChanged("BumpTexture");
                }
            }
        }
        private Bitmap _BumpTexture;

        public Bitmap SpecularTexture
        {
            get { return _SpecularTexture; }
            set
            {
                if (_SpecularTexture != value)
                {
                    RaisePropertyChanging("SpecularTexture");
                    _SpecularTexture = value;
                    RaisePropertyChanged("SpecularTexture");
                }
            }
        }
        private Bitmap _SpecularTexture;

        public Bitmap CloudsTexture
        {
            get { return _CloudsTexture; }
            set
            {
                if (_CloudsTexture != value)
                {
                    RaisePropertyChanging("CloudsTexture");
                    _CloudsTexture = value;
                    RaisePropertyChanged("CloudsTexture");
                }
            }
        }
        private Bitmap _CloudsTexture;
        
        public Bitmap SpriteTexture
        {
            get { return _SpriteTexture; }
            set
            {
                if (_SpriteTexture != value)
                {
                    RaisePropertyChanging("SpriteTexture");
                    _SpriteTexture = value;
                    RaisePropertyChanged("SpriteTexture");
                }
            }
        }
        private Bitmap _SpriteTexture;
        #endregion

        #region Event Handlers
        private void Moons_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
                foreach (Moon moon in e.NewItems)
                    moon.ParentOrthonormality = this;
            else if (e.Action == NotifyCollectionChangedAction.Remove)
                foreach (Moon moon in e.OldItems)
                    moon.ParentOrthonormality = null;
        }

        private void NearSpace_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (e.PropertyName == "Fleets" && !object.ReferenceEquals(NearSpace.Fleets, null))
                NearSpace.Fleets.CollectionChanged -= NearSpace_Fleets_CollectionChanged;
        }

        private void NearSpace_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Fleets" && !object.ReferenceEquals(NearSpace.Fleets, null))
                NearSpace.Fleets.CollectionChanged += NearSpace_Fleets_CollectionChanged;
        }

        private void NearSpace_Fleets_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var rnd = new Random(NearSpace.Fleets.Count);
                foreach (Fleet fleet in e.NewItems)
                {
                    var theta = (float)(rnd.NextDouble() * 2 * Math.PI);
                    var phi = (float)(rnd.NextDouble() * 2 * Math.PI);
                    fleet.Position = new Spherical(this.Radius * 5.0f, theta, phi);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (Fleet fleet in e.NewItems)
                {
                    fleet.Position = Spherical.Zero;
                }
            }
        }

        private void FarSpace_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            if (e.PropertyName == "Fleets" && !object.ReferenceEquals(FarSpace.Fleets, null))
                FarSpace.Fleets.CollectionChanged -= FarSpace_Fleets_CollectionChanged;
        }

        private void FarSpace_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Fleets" && !object.ReferenceEquals(FarSpace.Fleets, null))
                FarSpace.Fleets.CollectionChanged += FarSpace_Fleets_CollectionChanged;
        }

        private void FarSpace_Fleets_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var rnd = new Random(FarSpace.Fleets.Count);
                foreach (Fleet fleet in e.NewItems)
                {
                    var theta = (float)(rnd.NextDouble() * 2 * Math.PI);
                    var phi = (float)(rnd.NextDouble() * 2 * Math.PI);
                    fleet.Position = new Spherical(this.Radius * 20.0f, theta, phi);
                }
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                foreach (Fleet fleet in e.NewItems)
                {
                    fleet.Position = Spherical.Zero;
                }
            }
        }
        #endregion

        #region Rendering

        //private void InitializeComponent()
        //{
        //    _effect = this.CreateEffect(Properties.Resources.Planet);
        //    _renderLayout = this.CreateRenderLayout(_effect);
        //    _spriteLayout = this.CreateSpriteLayout(_effect);
        //    _trajLayout = this.CreateTrajectoryLayout(_effect);

        //    if (object.ReferenceEquals(this.Position, null))
        //        this.Position = new SphericalCS(0, 0, (float)Math.PI / 2);
        //    if (object.ReferenceEquals(this.Orientation, null))
        //        this.Orientation = RotationCS.Zero;
        //    if (object.ReferenceEquals(this.NearSpace, null))
        //        this.NearSpace = new SpaceRegion();
        //    if (object.ReferenceEquals(this.FarSpace, null))
        //        this.FarSpace = new SpaceRegion();

        //    this._effect.GetVariableByName("g_spriteDistance").AsScalar().Set(EngineParameters.SPRITE_DISTANCE);
        //    using (var bumpSRV = new ShaderResourceView(Engine.Current.Device, Properties.Resources.Neutral.ToTexture2D()))
        //        this._effect.GetVariableByName("bump_texture").AsResource().SetResource(bumpSRV);
        //    using (var atmosSRV = new ShaderResourceView(Engine.Current.Device, Properties.Resources.Neutral.ToTexture2D()))
        //        this._effect.GetVariableByName("atmos_texture").AsResource().SetResource(atmosSRV);

        //    this.HasClouds = false;
        //    this.CloudsHeight = 0;
        //    this.CloudsOpacity = 1.0f;
        //    this.CloudsSpeed = 0;

        //    this.HasAtmosphere = false;
        //    this.AtmosphereOpacity = 1.0f;
        //    this.AtmosphereRed = 25;
        //    this.AtmosphereGreen = 85;
        //    this.AtmosphereBlue = 200;

        //    float Kr = 0.0025f;
        //    float Km = 0.0015f;
        //    float ESun = 15.0f;
        //    float g = -0.95f;

        //    float KrESun = Kr * ESun;
        //    float KmESun = Km * ESun;
        //    float Kr4PI = Kr * 4 * (float)Math.PI;
        //    float Km4PI = Km * 4 * (float)Math.PI;
        //    float g2 = g * g;
        //    int nSamples = EngineParameters.ATMOSPHERE_SAMPLES;
        //    float fSamples = (float)Convert.ChangeType(EngineParameters.ATMOSPHERE_SAMPLES, typeof(float));

        //    this._effect.GetVariableByName("g_fKrESun").AsScalar().Set(KrESun);
        //    this._effect.GetVariableByName("g_fKmESun").AsScalar().Set(KmESun);
        //    this._effect.GetVariableByName("g_fKr4PI").AsScalar().Set(Kr4PI);
        //    this._effect.GetVariableByName("g_fKm4PI").AsScalar().Set(Km4PI);
        //    this._effect.GetVariableByName("g_nSamples").AsScalar().Set(nSamples);
        //    this._effect.GetVariableByName("g_fSamples").AsScalar().Set(fSamples);
        //    this._effect.GetVariableByName("g_fScaleDepth").AsScalar().Set(_scaleDepth);
        //    this._effect.GetVariableByName("g_g").AsScalar().Set(g);
        //    this._effect.GetVariableByName("g_g2").AsScalar().Set(g2);
        //}

        //protected internal override void Render3D()
        //{
        //    Vector3 lightPos = SceneHelper.GetLightPosition();
        //    Vector3 lightDir = lightPos - this.AbsolutePosition.Vector;
        //    Vector3 normalizedLightDir = Vector3.Normalize(lightDir);
        //    Vector3 cameraLocalPosition = SceneHelper.GetCameraPosition();
        //    float cameraHeight = CameraHelper.GetDistanceFromCamera(this);
        //    float cameraHeight2 = cameraHeight * cameraHeight;
        //    this._effect.GetVariableByName("g_fCameraHeight").AsScalar().Set(cameraHeight);
        //    this._effect.GetVariableByName("g_fCameraHeight2").AsScalar().Set(cameraHeight2);
        //    this._effect.GetVariableByName("g_vCameraLocalPosition").AsVector().Set(cameraLocalPosition);
        //    this._effect.GetVariableByName("g_vLightDirection").AsVector().Set(normalizedLightDir);

        //    base.Render3D();
        //}

        //void ITimeDependent.SetTime(long gameTime)
        //{
        //    SetTime(gameTime);
        //}

        //protected virtual void SetTime(long gameTime)
        //{
        //    this._effect.GetVariableByName("g_time").AsScalar().Set((float)gameTime);
        //}
        
        //protected override bool CanRender<T>(T objectToRender, float distanceToCamera)
        //{
        //    if (typeof(T) == typeof(IRender3D))
        //    {
        //        return distanceToCamera
        //        < this.Radius
        //        * EngineParameters.SYSTEM_MAX_RADIUS_PLANET;
        //        /// EngineParameters.CAMERA_REDUC_COEFF
        //        //* EngineParameters.SPACE_ELEMENT_ZOOM_COEFF;
        //    }
        //    else if (typeof(T) == typeof(IRenderSprite))
        //    {
        //        return true;
        //    }
        //    else if (typeof(T) == typeof(IRenderTrajectory))
        //    {
        //        return true;
        //    }
        //    else if (typeof(T) == typeof(IRender))
        //    {
        //        return true;
        //    }
        //    return false;
        //}
        #endregion

        #region ObservableObject Overrides
        protected override void OnPropertyChanging(PropertyChangingEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnPropertyChanging(e);

            if (e.PropertyName == "NearSpace" && !object.ReferenceEquals(this.NearSpace, null))
            {
                FarSpace.ParentOrthonormality = null;
                if (!object.ReferenceEquals(this.NearSpace.Fleets, null))
                    this.NearSpace.Fleets.CollectionChanged -= NearSpace_Fleets_CollectionChanged;
                NearSpace.PropertyChanging -= NearSpace_PropertyChanging;
                NearSpace.PropertyChanged -= NearSpace_PropertyChanged;
            }
            else if (e.PropertyName == "FarSpace" && !object.ReferenceEquals(this.FarSpace, null))
            {
                FarSpace.ParentOrthonormality = null;
                if (!object.ReferenceEquals(this.FarSpace.Fleets, null))
                    this.FarSpace.Fleets.CollectionChanged -= FarSpace_Fleets_CollectionChanged;
                FarSpace.PropertyChanging -= FarSpace_PropertyChanging;
                FarSpace.PropertyChanged -= FarSpace_PropertyChanged;
            }
        }

        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");

            base.OnPropertyChanged(e);

            if (e.PropertyName == "NearSpace" && !object.ReferenceEquals(this.NearSpace, null))
            {
                NearSpace.ParentOrthonormality = this;
                NearSpace.PropertyChanging += NearSpace_PropertyChanging;
                NearSpace.PropertyChanged += NearSpace_PropertyChanged;
                if (!object.ReferenceEquals(this.NearSpace.Fleets, null))
                    this.NearSpace.Fleets.CollectionChanged += NearSpace_Fleets_CollectionChanged;
            }
            else if (e.PropertyName == "FarSpace" && !object.ReferenceEquals(this.FarSpace, null))
            {
                FarSpace.ParentOrthonormality = this;
                FarSpace.PropertyChanging += FarSpace_PropertyChanging;
                FarSpace.PropertyChanged += FarSpace_PropertyChanged;
                if (!object.ReferenceEquals(this.FarSpace.Fleets, null))
                    this.FarSpace.Fleets.CollectionChanged += FarSpace_Fleets_CollectionChanged;
            }

            //if (e.PropertyName == "PhongExponent")
            //{
            //    this._effect.GetVariableByName("g_fPhongExponent").AsScalar().Set(PhongExponent);
            //}
            //else if (e.PropertyName == "PhongCoefficient")
            //{
            //    this._effect.GetVariableByName("g_fPhongCoefficient").AsScalar().Set(PhongCoefficient);
            //}
            //else if (e.PropertyName == "DiffuseCoefficient")
            //{
            //    this._effect.GetVariableByName("g_fDiffuseCoefficient").AsScalar().Set(DiffuseCoefficient);
            //}
            //else if (e.PropertyName == "HasClouds")
            //{
            //    this._effect.GetVariableByName("g_fHasClouds").AsScalar().Set(HasClouds);
            //}
            //else if (e.PropertyName == "CloudsSpeed")
            //{
            //    this._effect.GetVariableByName("g_fCloudSpeed").AsScalar().Set(CloudsSpeed);
            //}
            //else if (e.PropertyName == "CloudsHeight")
            //{
            //    this._effect.GetVariableByName("g_fCloudHeight").AsScalar().Set(CloudsHeight);
            //}
            //else if (e.PropertyName == "CloudsOpacity")
            //{
            //    this._effect.GetVariableByName("g_fCloudOpacity").AsScalar().Set(CloudsOpacity);
            //}
            //else if (e.PropertyName == "HasAtmosphere")
            //{
            //    this._effect.GetVariableByName("g_fHasAtmosphere").AsScalar().Set(HasAtmosphere);
            //}
            //else if (e.PropertyName == "AtmosphereSize")
            //{
            //    float outerRadius = Radius * (1.0f + _AtmosphereSize);
            //    float outerRadius2 = outerRadius * outerRadius;
            //    float scale = 1.0f / (outerRadius - Radius);
            //    float scaleOverScaleDepth = scale / _scaleDepth;
            //    this._effect.GetVariableByName("g_fOuterRadius").AsScalar().Set(outerRadius);
            //    this._effect.GetVariableByName("g_fOuterRadius2").AsScalar().Set(outerRadius2);
            //    this._effect.GetVariableByName("g_fScale").AsScalar().Set(scale);
            //    this._effect.GetVariableByName("g_fScaleOverScaleDepth").AsScalar().Set(scaleOverScaleDepth);
            //}
            //else if (e.PropertyName == "AtmosphereOpacity")
            //{
            //    this._effect.GetVariableByName("g_fAtmosphereOpacity").AsScalar().Set(AtmosphereOpacity);
            //}
            //else if (e.PropertyName == "AtmosphereRed")
            //{
            //    Vector3 waveLength = new Vector3(675 - _AtmosphereRed, 675 - _AtmosphereGreen, 675 - _AtmosphereBlue) / 1000;
            //    Vector3 g_vInvWavelength = new Vector3(
            //        1.0f / (float)Math.Pow(waveLength.X, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Y, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Z, 4.0f));
            //    this._effect.GetVariableByName("g_vInvWavelength").AsVector().Set(g_vInvWavelength);
            //}
            //else if (e.PropertyName == "AtmosphereGreen")
            //{
            //    Vector3 waveLength = new Vector3(675 - _AtmosphereRed, 675 - _AtmosphereGreen, 675 - _AtmosphereBlue) / 1000;
            //    Vector3 g_vInvWavelength = new Vector3(
            //        1.0f / (float)Math.Pow(waveLength.X, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Y, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Z, 4.0f));
            //    this._effect.GetVariableByName("g_vInvWavelength").AsVector().Set(g_vInvWavelength);
            //}
            //else if (e.PropertyName == "AtmosphereBlue")
            //{
            //    Vector3 waveLength = new Vector3(675 - _AtmosphereRed, 675 - _AtmosphereGreen, 675 - _AtmosphereBlue) / 1000;
            //    Vector3 g_vInvWavelength = new Vector3(
            //        1.0f / (float)Math.Pow(waveLength.X, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Y, 4.0f),
            //        1.0f / (float)Math.Pow(waveLength.Z, 4.0f));
            //    this._effect.GetVariableByName("g_vInvWavelength").AsVector().Set(g_vInvWavelength);
            //}
            //else if (e.PropertyName == "Radius")
            //{
            //    float innerRadius = Radius;
            //    float innerRadius2 = innerRadius * innerRadius;
            //    float outerRadius = innerRadius * _AtmosphereSize;
            //    float outerRadius2 = outerRadius * outerRadius;
            //    float scale = 1.0f / (outerRadius - innerRadius);
            //    float scaleOverScaleDepth = scale / _scaleDepth;
            //    this._effect.GetVariableByName("g_fInnerRadius").AsScalar().Set(innerRadius);
            //    this._effect.GetVariableByName("g_fInnerRadius2").AsScalar().Set(innerRadius2);
            //    this._effect.GetVariableByName("g_fOuterRadius").AsScalar().Set(outerRadius);
            //    this._effect.GetVariableByName("g_fOuterRadius2").AsScalar().Set(outerRadius2);
            //    this._effect.GetVariableByName("g_fScale").AsScalar().Set(scale);
            //    this._effect.GetVariableByName("g_fScaleOverScaleDepth").AsScalar().Set(scaleOverScaleDepth);
            //}
            //else if (e.PropertyName == "DiffuseTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "diffuse_texture", DiffuseTexture);
            //}
            //else if (e.PropertyName == "GlowTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "glow_texture", GlowTexture);
            //}
            //else if (e.PropertyName == "BumpTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "bump_texture", BumpTexture);
            //}
            //else if (e.PropertyName == "SpecularTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "reflection_texture", SpecularTexture);
            //}
            //else if (e.PropertyName == "CloudsTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "cloud_texture", CloudsTexture);
            //}
            //else if (e.PropertyName == "SpriteTexture")
            //{
            //    TextureHelper.SetTexture(this._effect, "sprite_texture", SpriteTexture);
            //}
        }
        #endregion

        #region IOrthonormality Implementation
        protected internal override IEnumerable<IPosition> ChildElements
        {
            get
            {
                var childs = new List<IPosition>();
                childs.AddRange(Moons);
                childs.Add(NearSpace);
                childs.Add(FarSpace);
                return childs;
            }
        }
        #endregion

        #region IEnvironment Implementation
        IEnumerable<ILocation> IEnvironment.Environment
        {
            get { return Environment; }
        }

        protected virtual IEnumerable<ILocation> Environment
        {
            get
            {
                return new List<ILocation>() { FarSpace, NearSpace };
            }
        }
        #endregion

        #region Serialization Members
        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] DiffuseTextureByteArray
        {
            get
            {
                if (this.DiffuseTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.DiffuseTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.DiffuseTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.DiffuseTexture = null;
            }
        }

        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] GlowTextureByteArray
        {
            get
            {
                if (this.GlowTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.GlowTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.GlowTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.GlowTexture = null;
            }
        }

        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] BumpTextureByteArray
        {
            get
            {
                if (this.BumpTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.BumpTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.BumpTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.BumpTexture = null;
            }
        }

        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] SpecularTextureByteArray
        {
            get
            {
                if (this.SpecularTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.SpecularTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.SpecularTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.SpecularTexture = null;
            }
        }

        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] CloudsTextureByteArray
        {
            get
            {
                if (this.CloudsTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.CloudsTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.CloudsTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.CloudsTexture = null;
            }
        }

        [DataMember]
        [SuppressMessage("Microsoft.Performance", "CA1811")]
        private byte[] SpriteTextureByteArray
        {
            get
            {
                if (this.SpriteTexture == null)
                    return null;
                using (var ms = new MemoryStream())
                {
                    this.SpriteTexture.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
            set
            {
                if (value != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        ms.Write(value, 0, value.Count());
                        this.SpriteTexture = new Bitmap(Image.FromStream(ms));
                    }
                }
                else
                    this.SpriteTexture = null;
            }
        }
        #endregion
    }
}
